<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        vertical-align: middle;
      }
      .btn-group {
        position: absolute;
      }
      .btn-group button {
        padding: 5px;
        display: inline-block;
      }
    </style>
  </head>
  <body>
    <div class="btn-group">
      <button id="warp">warp</button>
    </div>
    <!-- <img src="./princess.png" />
     -->
    <canvas id="canvas" style="background-color: blue"></canvas>
    <img
      src=""
      id="img"
    />
    <script>
      window.onload = () => {
        const canvas = document.querySelector("#canvas");
        canvas.height = window.innerHeight;
        canvas.width = window.innerWidth;
        const ctx = canvas.getContext("2d");

        class Particle {
          constructor(effect, x, y, color) {
            this.effect = effect;
            // 控制这 this.x 和 this.y 变化 都与不一样的效果
            this.x = Math.random() * this.effect.width;
            this.y = 0; // Math.random() * this.effect.height;
            this.originX = Math.floor(x);
            this.originY = Math.floor(y);
            this.color = color;
            this.size = this.effect.gap; // this.effect.gap - 1;
            this.vx = 0; // Math.random() * 2 - 1;
            this.vy = 0; // Math.random() * 2 - 1;

            this.ease = 0.02;
          }

          draw(context) {
            context.fillStyle = this.color;
            context.fillRect(this.x, this.y, this.size, this.size);
          }

          // update() {
          //   this.x += this.vx;
          //   this.y += this.vy;
          // }
          update() {
            this.x += (this.originX - this.x) * this.ease;
            this.y += (this.originY - this.y) * this.ease;
          }

          warp() {
            this.x = Math.random() * this.effect.width;
            this.y = Math.random() * this.effect.height;
            this.ease = 0.05;
          }
        }

        class Effect {
          constructor(width, height) {
            this.width = width;
            this.height = height;
            this.particlesArray = [];

            this.img = document.querySelector("#img");
            this.centerX = this.width / 2;
            this.centerY = this.height / 2;
            this.x = this.centerX - this.img.width / 2;
            this.y = this.centerY - this.img.height / 2;
            this.gap = 2; // 间隔多少取一个像素,这是看性能如何了，性能好，就取 1
          }

          init(context) {
            context.drawImage(this.img, this.x, this.y);
            const { width, height, gap } = this;
            // 取出图像的像素点
            const pixels = context.getImageData(0, 0, width, height).data;

            // 循环过滤出需要的像素点
            for (let y = 0; y < height; y += gap) {
              for (let x = 0; x < width; x += gap) {
                const index = (y * width + x) * 4; // 乘 4, 是因为，rgba 组成一个像素颜色
                const r = pixels[index];
                const g = pixels[index + 1];
                const b = pixels[index + 2];
                const a = pixels[index + 3];
                // 符合要求的当前位置的像素颜色
                const color = `rgb(${r}, ${g}, ${b})`;
                // 不是透明的就取出来
                if (a > 0) {
                  this.particlesArray.push(new Particle(this, x, y, color));
                }
              }
            }
          }

          draw(context) {
            this.particlesArray.forEach((particle) => particle.draw(context));
          }

          update() {
            this.particlesArray.forEach((particle) => particle.update());
          }

          warp() {
            this.particlesArray.forEach((particle) => particle.warp());
          }
        }

        const effect = new Effect(canvas.width, canvas.height);
        effect.init(ctx);

        function animate() {
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          effect.draw(ctx);
          effect.update();
          requestAnimationFrame(animate);
        }

        animate();

        const warp = document.querySelector("#warp");
        warp.onclick = () => {
          effect.warp();
        };
      };
    </script>
  </body>
</html>
